<?php

declare(strict_types=1);

namespace App\Common\Robot\Gateways;

use App\Common\Helpers\CommonUpload;
use App\Robot\Dto\ChatRecordMessageDTO;
use App\Robot\Dto\FileMessageDTO;
use App\Robot\Dto\GifMessageDTO;
use App\Robot\Dto\ImageMessageDTO;
use App\Robot\Dto\LocationMessageDTO;
use App\Robot\Dto\MiniProgramMessageDTO;
use App\Robot\Dto\SetProfileDTO;
use App\Robot\Dto\UrlMessageDTO;
use App\Robot\Dto\VideoChannelMessageDTO;
use App\Robot\Dto\VideoMessageDTO;
use App\Robot\Dto\VoiceMessageDTO;
use App\Setting\Service\SettingConfigService;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use Hyperf\Coroutine\Coroutine;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Redis\Redis;
use Mine\Exception\NormalStatusException;

class EasyWeWorkGateway extends Gateway
{

    #[Inject]
    protected Redis $redis;

    const GET_TOKEN_KEY = 'robot_easywork_token';


    /**
     * 创建实例
     * @param int $deviceType
     * @param string $deviceName
     * @param string $proxyUrl
     * @param string $clientVersion
     * @return mixed
     */
    public function createClient(int $deviceType = 1,string $deviceName = '',string $proxyUrl = '',string $clientVersion = ''): mixed
    {
        $response = $this->post('/client/createClient', [
            'deviceType' => $deviceType,
            'deviceName' => $deviceName,
            'proxyUrl' => $proxyUrl,
            'clientVersion' => $clientVersion,
        ]);
        return $response;
    }

    public function getClientList()
    {
        $response = $this->get('/client/list');
        return $response;
    }


    public function stopClient()
    {
        $response = $this->post('client/stopClient', [
            'guid' => $this->uuid
        ]);
        return $response;
    }

    /**
     * 恢复实例
     * @param string $logUserId 没有时可为空；不为空时则会检测本地数据，并在免验证的规则下尝试自动登陆
     * @param string $customerParam 自定义参数
     * @param int $deviceType
     * @return mixed
     */
    public function restoreClient(string $logUserId = '',string $customerParam = '',string $proxyUrl = '',int $onlyProxyLogin = 1,int $deviceType = 1): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'logUserId' => $logUserId,
            'deviceType' => $deviceType,
            'customerParam' => $customerParam
        ];

        if(!empty($proxyUrl)){
            $data['proxyUrl'] = $proxyUrl;
            $data['onlyProxyLogin'] = $onlyProxyLogin;
        }

//        $clientVersion = container()->get(SettingConfigService::class)->getConfigByKey('qw_client_version')['value'] ?? '';
//        if(!empty($clientVersion)){
//            logger()->info($this->uuid.'当前登录版本为：'.$clientVersion);
//            $data['clientVersion'] = $clientVersion;
//        }

        $response = $this->toPost('/client/restoreClient', $data);
        return $response;
    }

    public function manualLogin(string $userId,string $customerParam = '',string $proxyUrl = '',int $onlyProxyLogin = 1,int $deviceType = 1):mixed
    {
        $this->toPost('/client/stopClient', [
            'guid' => $this->uuid
        ]);
        $response = $this->restoreClient($userId,$customerParam,$proxyUrl,$onlyProxyLogin,$deviceType);
//        if($response !== false){
//            $response = $this->toPost('/login/checkLogin', [
//                'guid' => $this->uuid
//            ]);
//            if($response === false || $response['user_online_status'] != 2){
//                $this->toPost('/client/stopClient', [
//                    'guid' => $this->uuid
//                ]);
//                return false;
//            }
//        }
        return $response;
    }

    /**
     * 取消代理
     * @return mixed
     */
    public function cancelProxy(): mixed
    {
        $response = $this->toPost('/login/cancelProxy', [
            'guid' => $this->uuid,
        ]);
        return $response;
    }


    public function checkLogin(): mixed
    {
        $response = $this->toPost('/login/checkLogin', [
            'guid' => $this->uuid,
        ]);
        return $response;
    }


    public function setNotifyUrl(string $notifyUrl)
    {
        $response = $this->post('client/setNotifyUrl', [
            'url' => $notifyUrl,
        ]);
        return $response;
    }

    public function delNotifyUrl(string $notifyUrl)
    {
        $response = $this->post('client/delNotifyUrl', [
            'url' => $notifyUrl,
        ]);
        return $response;
    }

    /**
     * 获取登录二维码
     * @param string $customerParam
     * @return mixed
     */
    public function getLoginQrCode(string $customerParam,string $proxyUrl = '',int $onlyProxyLogin = 1): mixed
    {
        $response = $this->restoreClient('',$customerParam,$proxyUrl,$onlyProxyLogin);
        if($response === false){
            return false;
        }
        
        $response = $this->toPost('/login/getLoginQrcode', [
            'guid' => $this->uuid,
        ]);
        return $response;
    }

    public function checkLoginQrCode(): mixed
    {
        $response = $this->toPost('/login/checkLoginQrCode', [
            'guid' => $this->uuid,
        ]);
        return $response;
    }

    public function verifyLoginQrcode(string $code, string $loginQrcodeKey = ''): mixed
    {
        $response = $this->toPost('/login/verifyLoginQrcode',[
            'guid' => $this->uuid,
            'code' => $code,
        ]);
        return $response;
    }

    public function loginOut(): mixed
    {
        $response = $this->toPost('/user/logout', [
            'guid' => $this->uuid
        ]);
        return $response;
    }

    public function getEmployeeList(string $currentVersion = '', int $limit = null): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'clientVersion' => $currentVersion
        ];

        if(!is_null($limit)){
            $data['limit'] = $limit;
        }

        $response = $this->toPost('/contact/getWxWorkContactList', $data);
        return $response;
    }

    public function getEmployeeDetail(array $userIdList): mixed
    {
        $response = $this->toPost('/contact/batchGetUserinfo', [
            'guid' => $this->uuid,
            'userIdList' => $userIdList
        ]);
        return $response;
    }

    public function getProfile(string $userId = ''): mixed
    {
        $response = $this->toPost('/user/getProfile', [
            'guid' => $this->uuid,
        ]);
        return $response;
    }

    public function setProfile(SetProfileDTO $data): mixed
    {
        $response = $this->toPost('/user/setProfile', array_merge([
            'guid' => $this->uuid,
        ], $data->toArray()));
        return $response;
    }

    public function getPersonalQRCode(): mixed
    {
        $response = $this->toPost('/user/getQrcodeCard', [
            'guid' => $this->uuid
        ]);
        return $response;
    }

    public function syncCollectionMsg(int $seq = 0, int $limit = null): mixed
    {
        $response = $this->toPost('/msg/syncCollectionMsg', [
            'guid' => $this->uuid,
            'seq' => $seq,
            'limit' => $limit
        ]);
        return $response;
    }

    public function insertCollectionMsg(array $msgData, int $type = 29): mixed
    {
        $response = $this->toPost('/msg/syncCollectionMsg', [
            'guid' => $this->uuid,
            'msgData' => $msgData,
            'type' => $type
        ]);
        return $response;
    }

    public function getCorpInfo(array $corpIdList = []): mixed
    {
        $response = $this->toPost('/user/getCorpInfo',[
            'guid' => $this->uuid,
            'corpIdList' => $corpIdList
        ]);
        return $response;
    }

    public function getTagList(int $labelType, int $currentSeq = 0): mixed
    {
        $response = $this->toPost('/label/syncLabelList', [
            'guid' => $this->uuid,
            'currentSeq' => $currentSeq,
            'labelType' => $labelType
        ]);
        return $response;
    }

    public function editLabel(int $opType, array $paramList): mixed
    {
        $response = $this->toPost('/label/editLabel', [
            'guid' => $this->uuid,
            'opType' => $opType,
            'paramList' => $paramList
        ]);
        return $response;
    }

    public function contactEditLabel(int $opType, array $paramList): mixed
    {
        $response = $this->toPost('/label/contactEditLabel', [
            'guid' => $this->uuid,
            'opType' => $opType,
            'paramList' => $paramList
        ]);
        return $response;
    }

    public function getContactList(int $currentSeq = 0, $limit = null, int $bizType = null): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'currentSeq' => $currentSeq
        ];

        if(!is_null($limit)){
            $data['limit'] = $limit;
        }

        if(!is_null($bizType)){
            $data['bizType'] = $bizType;
        }

        $response = $this->toPost('/contact/getWxContactList', $data);
        return $response;
    }

    public function searchContact(string $keyword): mixed
    {
        $response = $this->toPost('/contact/searchContact', [
            'guid' => $this->uuid,
            'keyword' => $keyword
        ]);
        return $response;
    }

    public function addSearchWxContact(string $userId, string $unionId, string $verifyText = ''): mixed
    {
        $response = $this->toPost('/contact/addSearchWxContact', [
            'guid' => $this->uuid,
            'userId' => $userId,
            'unionId' => $unionId,
            'verifyText' => $verifyText
        ]);
        return $response;
    }

    public function addSearchWxWorkContact(string $userId, string $corpId, string $ticket, string $verifyText = ''): mixed
    {
        $response = $this->toPost('/contact/addSearchWxWorkContact', [
            'guid' => $this->uuid,
            'userId' => $userId,
            'corpId' => $corpId,
            'ticket' => $ticket,
            'verifyText' => $verifyText
        ]);
        return $response;
    }

    public function addCardContact(string $presenterId, string $fromRoomId, string $userId, string $verifyText): mixed
    {
        $response = $this->toPost('/contact/addCardContact', [
            'guid' => $this->uuid,
            'presenterId' => $presenterId,
            'fromRoomId' => $fromRoomId,
            'userId' => $userId,
            'verifyText' => $verifyText
        ]);
        return $response;
    }

    public function addDeletedContact(string $userId, string $verifyText): mixed
    {
        $response = $this->toPost('/contact/addDeletedContact', [
            'guid' => $this->uuid,
            'userId' => $userId,
            'verifyText' => $verifyText
        ]);
        return $response;
    }

    public function agreeContact(string $userId, string $corpId): mixed
    {
        $response = $this->toPost('/contact/agreeContact', [
            'guid' => $this->uuid,
            'userId' => $userId,
            'corpId' => $corpId
        ]);
        return $response;
    }


    public function getContactDetail(array $useridList): mixed
    {
        $response = $this->toPost('/contact/batchGetUserinfo', [
            'guid' => $this->uuid,
            'userIdList' => $useridList
        ]);
        return $response;
    }

    public function updateWxContact(string $userid, string $remark, string $desc, string $corpRemark, array $mobileList, array $labelList): mixed
    {
        $newLabelList = [];
        $newLabelList['labelIdList'] = [];
        $newLabelList['labelSuperIdList'] = [];
        $newLabelList['labelOwnerList'] = [];
        foreach ($labelList as $label){
            $newLabelList['labelIdList'][] = $label['label_id'];
            $newLabelList['labelSuperIdList'][] = $label['group_id'];
            $newLabelList['labelOwnerList'][] = $label['owner_id'];
        }

        $response = $this->toPost('/contact/updateWxContact', [
            'guid' => $this->uuid,
            'userId' => $userid,
            'remark' => $remark,
            'desc' => $desc,
            'corpRemark' => $corpRemark,
            'mobileList' => $mobileList,
            'labelList' => $newLabelList
        ]);
        return $response;
    }

    public function updateWxWorkContact(string $userid, string $remark, string $desc): mixed
    {
        $response = $this->toPost('/contact/updateWxWorkContact', [
            'guid' => $this->uuid,
            'userId' => $userid,
            'remark' => $remark,
            'desc' => $desc
        ]);
        return $response;
    }

    public function deleteContact(mixed $userId): mixed
    {
        $response = $this->toPost('/contact/deleteContact', [
            'guid' => $this->uuid,
            'userId' => $userId
        ]);
        return $response;
    }

    public function useridToOpenuserid(array $userIdList): mixed
    {
        $response = $this->toPost('/contact/openid', [
            'guid' => $this->uuid,
            'userIdList' => $userIdList
        ]);

        if($response !== false){
            return $response['open_user_list'];
        }

        return false;
    }


    public function getSessionPage(int $currentSeq = 0, int $limit = null): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'currentSeq' => $currentSeq
        ];

        if(!is_null($limit)){
            $data['limit'] = $limit;
        }

        $response = $this->toPost('/session/getSessionPage', $data);
        return $response;
    }

    public function setSessionCmd(string $chatId, int $chatType): mixed
    {
        $response = $this->toPost('/session/setSessionCmd', [
            'guid' => $this->uuid,
            'chatId' => $chatId,
            'chatType' => $chatType
        ]);
        return $response;
    }

    public function getSessionList(int $getFlag = null): mixed
    {
        $response = $this->toPost('/session/getSessionList', [
            'guid' => $this->uuid,
        ]);
        return $response;
    }


    public function getCallingInfo(): array
    {
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 4);
        // 查找调用者（跳过当前方法getCallingInfo和调用此方法的方法）
        $callingFunction = $trace[2]['function'] ?? 'unknown';
        $callingClass = $trace[2]['class'] ?? 'unknown';
        // 获取更上一级的调用者（如果有）
        $previousCaller = $trace[3] ?? [];

        return [
            'calling_class' => $callingClass,
            'calling_function' => $callingFunction,
            'previous_caller' => $previousCaller,
            'full_trace' => $trace // 完整回溯信息，用于调试
        ];
    }

    public function createRoom(array $memberList, int $isOuterRoom = 1): mixed
    {
        logger()->info('创建群聊'.$this->uuid.'----'.json_encode($memberList));
        $callingInfo = $this->getCallingInfo();
        logger()->info('创建群聊调用信息: ' . json_encode($callingInfo));
        if(empty($memberList)){
            return false;
        }
        $response = $this->toPost('/room/createRoom', [
            'guid' => $this->uuid,
            'isOuterRoom' => $isOuterRoom,
            'memberList' => $memberList
        ]);
        return $response;
    }

    public function editRoomName(mixed $roomId, string $roomName): mixed
    {
        $response = $this->toPost('/room/modifyRoomName', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
            'name' => $roomName
        ]);
        return $response;
    }

    public function generateRoomQRCode(mixed $roomId): mixed
    {
        $response = $this->post('/room/getRoomQrCode', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
        ]);
        return $response;
    }


    public function transferRoomOwner(mixed $roomId, mixed $newOwnerId): mixed
    {
        $response = $this->toPost('/room/changeRoomMaster', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
            'newOwnerId' => $newOwnerId
        ]);
        return $response;
    }

    public function setRoomAdmin(mixed $roomId, array $memberList, bool $isSet = true): mixed
    {
        $uri = $isSet ? '/room/roomAddAdmin' : '/room/roomRemoveAdmin';
        $response = $this->toPost($uri, [
            'guid' => $this->uuid,
            'roomId' => $roomId,
            'memberList' => $memberList
        ]);
        return $response;
    }

    public function outRoom(mixed $roomId): mixed
    {
        $response = $this->toPost('/room/quitRoom', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
        ]);
        return $response;
    }

    public function removeRoomMember(mixed $roomId, array $memberList, int $isOuterRoom = 1): mixed
    {
        $response = $this->toPost('/room/removeRoomMember', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
            'isOuterRoom' => $isOuterRoom,
            'memberList' => $memberList
        ]);
        return $response;
    }

    public function getRoomList(int $nextStartIndex = 0, int $limit = null): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'nextStartIndex' => $nextStartIndex
        ];

        if(!is_null($limit)){
            $data['limit'] = $limit;
        }

        $response = $this->toPost('/room/getRoomList', $data);
        return $response;
    }

    public function getRoomDetail(array $roomIdList): mixed
    {
        $response = $this->toPost('/room/batchGetRoomDetail', [
            'guid' => $this->uuid,
            'roomIdList' => $roomIdList
        ]);

        if($response !== false){
            return $response['room_list'];
        }
        return false;
    }

    public function postGrpAnn(mixed $roomId, string $notice): mixed
    {
        $response = $this->toPost('/room/modifyRoomNotice', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
            'notice' => $notice
        ]);
        return $response;
    }


    public function inviteFriendToRoom(string $roomId, array $memberList, int $isOuterRoom = 1): mixed
    {
        stdout_log()->info('发送群成员入群');
        $response = $this->toPost('/room/inviteRoomMember', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
            'isOuterRoom' => $isOuterRoom,
            'memberList' => $memberList,
        ]);
        return $response;
    }

    /**
     * 群成员邀请确认
     * @param string $roomId
     * @param string $inviterId
     * @param string $inviteMsgServerId
     * @param string $inviteCode
     * @param array $invitedMemberList
     * @return mixed
     */
    public function confirmInvitedMemberList(string $roomId, string $inviterId, string $inviteMsgServerId, string $inviteCode, array $invitedMemberList): mixed
    {
        $response = $this->toPost('/room/confirmInvitedMemberList', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
            'inviterId' => $inviterId,
            'inviteMsgServerId' => $inviteMsgServerId,
            'inviteCode' => $inviteCode,
            'invitedMemberList' => $invitedMemberList
        ]);
        return $response;
    }


    public function dismissRoom(mixed $roomId): mixed
    {
        $response = $this->toPost('/room/dismissRoom', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
        ]);
        return $response;
    }

    public function roomidToOpenroomid(string $roomId): mixed
    {
        $response = $this->toPost('/room/openid', [
            'guid' => $this->uuid,
            'roomId' => $roomId,
        ]);
        return $response;
    }


    public function sendTextMsg(string $content, string $toId, array $reply = []): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'content' => $content,
            'toId' => $toId,
        ];

        if(!empty($reply)){
            $data['reply'] = $reply;
        }
        $response = $this->toPost('/msg/sendText', $data);
        return $response;
    }

    public function sendMixTxtMsg(array $content, string $toId, array $reply = []): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'content' => $content,
            'toId' => $toId,
        ];

        if(!empty($reply)){
            $data['reply'] = $reply;
        }
        $response = $this->toPost('/msg/sendHyperText', $data);
        return $response;
    }

    public function sendImageMsg(ImageMessageDTO $imageMessage): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$imageMessage->toArray());
        $response = $this->toPost('/msg/sendImage', $data);
        return $response;
    }

    public function sendGif(GifMessageDTO $gifMessageDTO): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$gifMessageDTO->toArray());
        $response = $this->toPost('/msg/sendGif', $data);
        return $response;
    }


    public function sendVideoMsg(VideoMessageDTO $videoMessage): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$videoMessage->toArray());
        $response = $this->toPost('/msg/sendVideo', $data);
        return $response;
    }

    public function sendFileMsg(FileMessageDTO $fileMessageDTO): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$fileMessageDTO->toArray());
        $response = $this->toPost('/msg/sendFile', $data);
        return $response;
    }

    public function sendVoiceMsg(VoiceMessageDTO $voiceMessageDTO): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$voiceMessageDTO->toArray());
        $response = $this->toPost('/msg/sendVoice', $data);
        return $response;
    }

    public function sendUrlMsg(UrlMessageDTO $urlMessageDTO): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$urlMessageDTO->toArray());
        $response = $this->toPost('/msg/sendLink', $data);
        return $response;
    }

    public function sendMiniProgram(MiniProgramMessageDTO $miniProgramMessageDTO): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$miniProgramMessageDTO->toArray());
        $response = $this->toPost('/msg/sendWeapp', $data);
        return $response;
    }

    public function sendPersonalCard(string $sharedId, string $toId): mixed
    {
        $response = $this->toPost('/msg/sendPersonalCard', [
            'guid' => $this->uuid,
            'sharedId' => $sharedId,
            'toId' => $toId,
        ]);
        return $response;
    }

    public function sendLocation(LocationMessageDTO $locationMessageDTO): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$locationMessageDTO->toArray());
        $response = $this->toPost('/msg/sendLocation', $data);
        return $response;
    }

    public function sendVideoChannelMsg(VideoChannelMessageDTO $videoChannelMessageDTO): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$videoChannelMessageDTO->toArray());
        $response = $this->toPost('/msg/sendFeedVideo', $data);
        return $response;
    }

    /**
     * 发送聊天记录消息
     * @param ChatRecordMessageDTO $chatRecordMessageDTO
     * @return mixed
     */
    public function sendChatRecord(ChatRecordMessageDTO $chatRecordMessageDTO): mixed
    {
        $data = array_merge(['guid' => $this->uuid],$chatRecordMessageDTO->toArray());
        $response = $this->toPost('/msg/sendChatRecord', $data);
        return $response;
    }


    public function revokeMsg(string $chatId, int $msgServerId): mixed
    {
        $response = $this->toPost('/msg/revokeMsg', [
            'guid' => $this->uuid,
            'chatId' => $chatId,
            'msgServerId' => $msgServerId,
        ]);
        return $response;
    }


    public function upload(string $url, string $filename, int $fileType): mixed
    {
        $response = $this->toPost('/cloud/cdnBigUploadByUrl', [
            'guid' => $this->uuid,
            'filename' => $filename,
            'fileUrl' => $url,
            'fileType' => $fileType
        ]);
        return $response;
    }

    public function cdnBigUpload(string $url, string $filename, int $fileType): mixed
    {
        $multipart = [
            [
                'name'     => 'guid',
                'contents' => $this->uuid,
            ]
        ];
        $uri = '/cloud/cdnBigUpload';
        $isBigFile = false;
        try {
            $response = $this->client->get($url);
            $contents = $response->getBody();
            $sizeInBytes = $contents->getSize();
            // 如果 getSize() 返回 null，则尝试从响应头获取
            if ($sizeInBytes === null) {
                $sizeInBytes = $response->getHeaderLine('Content-Length');
                $sizeInBytes = $sizeInBytes ? (int)$sizeInBytes : 0;
            }

            // 转换为 MB，保留两位小数
            $sizeInMB = $sizeInBytes > 0 ? round($sizeInBytes / (1024 * 1024), 2) : 0;
            $sizeInMB > 20 && $uri = '/sns/upload';

            if($sizeInMB > 20){
                $uri = '/sns/upload';
                $fileType = 35;
                $isBigFile = true;

            }
            $multipart[] = [
                'name'     => 'fileType',
                'contents' => (string)$fileType,
            ];
            empty($filename) && $filename = get_remote_file_name($url);
            $multipart[] = [
                'name'     => 'file',
                'contents' => $contents,
                'filename' => $filename,
            ];
        } catch (GuzzleException $e) {
            return false;
        }
        $response = $this->toPost($uri, $multipart,true);
        if($response !== false){
            if(isset($response['file_convert_id'])){
                $response['file_id'] = $response['file_convert_id'];
            }
            !isset($response['file_aes_key']) && $response['file_aes_key'] = '';
        }
        return $response;
    }

    public function wxWorkDownload(string $fileAeskey, string $fileId, int $fileSize, int $fileType, string $filename = ''): mixed
    {
        $response = $this->toPost('/cloud/wxWorkDownload', [
            'guid' => $this->uuid,
            'fileAeskey' => $fileAeskey,
            'fileId' => $fileId,
            'fileSize' => $fileSize,
            'fileType' => $fileType
        ]);

        if($response !== false){
            $filename = get_remote_file_name($response['cloud_url']);
            $data['url'] = container()->get(CommonUpload::class)->uploadRemoteFile($response['cloud_url'],$filename);
            return $data;
        }

        return false;
    }

    public function wxDownload(string $fileAeskey, string $fileAuthkey, int $fileSize, string $fileUrl, int $fileType, string $filename = ''): mixed
    {
        $response = $this->toPost('/cloud/wxDownload', [
            'guid' => $this->uuid,
            'fileAeskey' => $fileAeskey,
            'fileAuthkey' => $fileAuthkey,
            'fileSize' => $fileSize,
            'fileUrl' => $fileUrl,
            'fileType' => $fileType
        ]);

        if($response !== false){
            $filename = get_remote_file_name($response['cloud_url']);
           $data['url'] = container()->get(CommonUpload::class)->uploadRemoteFile($response['cloud_url'],$filename);
           return $data;
        }

        return false;
    }


    public function cdnToUrl(string $fileAesKey, string $fileId, string $fileMd5): mixed
    {
        $response = $this->toPost('/cloud/cdnWxDownload', [
            'guid' => $this->uuid,
            'fileAeskey' => $fileAesKey,
            'fileId' => $fileId,
            'fileMd5' => $fileMd5
        ]);
        return $response;
    }

    /**
     * cdn数据刷新
     * @return mixed
     */
    public function cdnRefresher(): mixed
    {
        $response = $this->toPost('/cloud/updateCdnRule', [
            'guid' => $this->uuid
        ]);
        return $response;
    }


    public function getSnsRecord(int $minSnsId = 0, int $limit = null): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'minSnsId' => $minSnsId,
        ];

        if(!is_null($limit)){
            $data['limit'] = $limit;
        }

        $response = $this->toPost('/sns/getSnsRecord', $data);
        return $response;
    }


    public function getSnsDetail(array $snsIdList): mixed
    {
        $response = $this->toPost('/sns/getSnsDetail', [
            'guid' => $this->uuid,
            'snsIdList' => $snsIdList
        ]);
        return $response;
    }


    public function snsUpload(mixed $file, int $fileType): mixed
    {
        $multipart = [
            [
                'name'     => 'guid',
                'contents' => $this->uuid,
            ],
            [
                'name'     => 'fileType',
                'contents' => (string)$fileType,
            ],
        ];

        try {
            $response = $this->client->get($file);
            $contents = $response->getBody();
            $filename = get_remote_file_name($file);
            $multipart[] = [
                'name'     => 'file',
                'contents' => $contents,
                'filename' => $filename,
            ];
        } catch (GuzzleException $e) {
            return false;
        }

        $response = $this->toPost('/sns/upload', $multipart,true);
        if($response !== false){
            $response['file_id'] = $response['file_convert_id'];
        }
        return $response;
    }

    public function postSns(int $postType, string $content, array $mediaList, array $linkInfo, array $visibleUserIdList = []): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'postType' => $postType,
            'content' => $content,
        ];

        !empty($mediaList) && $data['mediaList'] = $mediaList;
        !empty($linkInfo) && $data['linkInfo'] = $linkInfo;
        !empty($visibleUserIdList) && $data['visibleUserIdList'] = $visibleUserIdList;
        $response = $this->toPost('/sns/postSns', $data);
        return $response;
    }

    public function snsLike(int $snsId, int $snsStatus = 0): mixed
    {
        $response = $this->toPost('/sns/snsLike', [
            'guid' => $this->uuid,
            'snsId' => $snsId,
            'snsStatus' => $snsStatus
        ]);
        return $response;
    }

    public function snsComment(int $snsId, string $content, int $refCommentId = 0): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'snsId' => $snsId,
            'content' => $content,
            'refCommentId' => $refCommentId
        ];

        $response = $this->toPost('/sns/snsComment', $data);
        return $response;
    }

    public function deleteSnsComment(int $snsId, int $commentId): mixed
    {
        $response = $this->toPost('/sns/deleteSnsComment', [
            'guid' => $this->uuid,
            'snsId' => $snsId,
            'commentId' => $commentId
        ]);
        return $response;
    }


    public function deleteSns(int $snsId): mixed
    {
        $response = $this->toPost('/sns/deleteSns', [
            'guid' => $this->uuid,
            'snsId' => $snsId
        ]);
        return $response;
    }

    public function dataSync(int $businessId, int $msgSeq = 0,int $limit = null): mixed
    {
        $data = [
            'guid' => $this->uuid,
            'currentSeq' => $msgSeq,
            'bizType' => $businessId
        ];

        if(!is_null($limit)){
            $data['limit'] = $limit;
        }
        $response = $this->toPost('/contact/getWxContactList', $data);
        return $response;
    }


    public function getToken()
    {
        $key = self::GET_TOKEN_KEY.':'.md5($this->config['appId'].$this->config['appSecret']);
        $tokenData = $this->redis->get($key);
        if(empty($tokenData)){
            $response = $this->post('/member/login', [
                'appId' => $this->config['appId'],
                'appSecret' => $this->config['appSecret'],
            ]);

            if($response !== false){
                $this->redis->set($key, $response, 3600);
                return $response['token'];
            }
            return '';
        }
        $expire = strtotime($tokenData['expire']);
        if($expire < time()){
            $response = $this->post('/member/refreshToken');

            if($response !== false){
                $this->redis->set($key, $response, 3600);
                return $response['token'];
            }
            return '';
        }
        return $tokenData['token'];
    }

    protected function post($uri, $data = [],bool $isMultipart = false): mixed
    {
        try{
            $headers = [];
            if($uri !== '/member/login'){
                $headers = [
                    'Authorization' => 'Bearer '.$this->getToken()
                ];
            }
            $options = $isMultipart ? ['multipart' => $data] : ['json' => $data];

            $response = $this->client->post($uri, array_merge([
                'headers' => $headers,
                'on_stats' => function (\GuzzleHttp\TransferStats $stats) use ($uri) {
                    if(env('IS_LOCAL')){
                        // 获取请求信息
                        $request = $stats->getRequest();
                        $rawRequest = sprintf(
                            "%s %s HTTP/%s\r\n%s\r\n\r\n%s",
                            $request->getMethod(),
                            $request->getRequestTarget(),
                            $request->getProtocolVersion(),
                            implode("\r\n", array_map(
                                fn($k, $v) => $k.': '.$v[0],
                                array_keys($request->getHeaders()),
                                array_values($request->getHeaders())
                            )),
                            (string)$request->getBody()
                        );
                        stdout_log()->info("原始请求报文：\n".$rawRequest);
                    }
                }
            ],$options));

            if(env('IS_LOCAL')){
                // 记录响应信息
                $rawResponse = sprintf(
                    "HTTP/%s %s %s\r\n%s\r\n\r\n%s",
                    $response->getProtocolVersion(),
                    $response->getStatusCode(),
                    $response->getReasonPhrase(),
                    implode("\r\n", array_map(
                        fn($k, $v) => $k.': '.$v[0],
                        array_keys($response->getHeaders()),
                        array_values($response->getHeaders())
                    )),
                    (string)$response->getBody()
                );
                stdout_log()->info("原始响应报文：\n".$rawResponse);
            }

            $response = $this->packer->unpack((string)$response->getBody());
//            $now = Carbon::now()->toDateTimeString();
//            logger()->info("{$this->uuid}请求{$uri}参数{$now}：".json_encode($data));
//            logger()->info("{$this->uuid}请求{$uri}返回{$now}：".json_encode($response,JSON_UNESCAPED_UNICODE));
            if ($response['code'] != 0) {
                if($this->throw){
                    throw new NormalStatusException($response['msg']);
                }else{
                    $this->errorMsg = $response['msg'];
                    logger()->info("【{$uri}】机器人接口请求返回失败入参：".json_encode($data));
                    logger()->info("【{$uri}】机器人接口请求返回失败结果：".json_encode($response));
                    return false;
                }
            }
            $data =  $response['data'] ?? [];
            return camelToUnder($data);
        }catch(\Throwable $e){
            logger()->info("{$this->uuid}【{$uri}】请求失败：".$e->getMessage());
            return false;
        }
    }

    protected function get($uri, $data = []): mixed
    {
        try{
            $headers = [
                'Authorization' => 'Bearer '.$this->getToken()
            ];

            $response = $this->client->post($uri, [
                'headers' => $headers,
                'query' => $data
            ]);
            $response = $this->packer->unpack((string)$response->getBody());
            if ($response['code'] != 0) {
                if($this->throw){
                    throw new NormalStatusException($response['msg']);
                }else{
                    $this->errorMsg = $response['msg'];
                    logger()->info("【{$uri}】机器人接口请求返回失败入参：".json_encode($data,JSON_UNESCAPED_UNICODE));
                    logger()->info("【{$uri}】机器人接口请求返回失败结果：".json_encode($response,JSON_UNESCAPED_UNICODE));
                    return false;
                }
            }
            return $response['data'] ?? [];
        }catch(\Throwable $e){
            logger()->info("【{$uri}】请求失败：".$e->getMessage());
            return false;
        }
    }

    public function sendGroupMsg(array $msgList,int $sendType,array $toIdList): mixed
    {
        logger()->info('极速群发入参'.json_encode([
                'guid' => $this->uuid,
                'msgList' => $msgList,
                'sendType' => $sendType,
                'toIdList' => $toIdList
            ]));
        $response = $this->toPost('/msg/sendGroupMsg', [
            'guid' => $this->uuid,
            'msgList' => $msgList,
            'sendType' => $sendType,
            'toIdList' => $toIdList
        ]);
        return $response;
    }

    public function queryGroupMsgEnabledMembers(array $userIdList,int $sendType): mixed
    {
        $response = $this->toPost('/msg/queryGroupMsgEnabledMembers', [
            'guid' => $this->uuid,
            'userIdList' => $userIdList,
            'sendType' => $sendType,
        ]);
        return $response;
    }
}